Material and idea Source: https://github.com/bupaverse

1. Scenario 1

1.1 Read data

sc1_data <- read.csv("C:/Users/nikol/Downloads/scenario1.csv", sep=";")

1.2 Analyze data structure

head(sc1_data)

1.3 Data wrangling

sc1_activitylog <- sc1_data %>%
    # rename timestamp variables appropriately
    dplyr::rename(start = activity_started, 
           complete = activity_ended) %>%
    # convert timestamps to 
    convert_timestamps(columns = c("start", "complete"), format = ymd_hms) %>%
    activitylog(case_id = "patient",
                activity_id = "handling",
                resource_id = "employee",
                timestamps = c("start", "complete"))

1.4 Data visualization

1.4.1 Processmap, frequency

#frequency: absolute, absolute_case, relative, relative_case
print(process_map(sc1_activitylog, type=frequency("absolute")))
NULL

1.4.2 Processmap, performance

#performance: median/mean, "years"/"semesters"/"quarters"/"months"/"weeks"/"days"/"hours"/"mins"/"secs"
print(process_map(sc1_activitylog, type=performance(median,"secs")))
NULL

1.4.3 Ressourcemap, frequency

resource_map(sc1_activitylog, type=frequency("absolute"))

1.4.5 Ressourcemap, performance

resource_map(sc1_activitylog, type=performance(median,"secs"))

2. Scenario 2

2.1 Read data

sc2_data <- read.csv("C:/Users/nikol/Downloads/scenario2.csv", sep=";")

2.2 Analyze data structure

head(sc2_data)

2.3 Data wrangling

sc2_data %>%
    # recode lifecycle variable appropriately
    dplyr::mutate(registration_type = forcats::fct_recode(registration_type, 
                                                          "start" = "started",
                                                          "complete" = "completed")) %>%
    convert_timestamps(columns = "time", format = ymd_hms) %>%
    eventlog(case_id = "patient",
             activity_id = "handling",
             activity_instance_id = "handling_id",
             lifecycle_id = "registration_type",
             timestamp = "time",
             resource_id = "employee") %>%
    to_activitylog() -> sc2_activitylog

sc2_activitylog
# Log of 10 events consisting of:
1 trace 
1 case 
5 instances of 5 activities 
5 resources 
Events occurred from 2018-09-20 17:16:02 until 2021-09-20 17:03:14 
 
# Variables were mapped as follows:
Case identifier:        patient 
Activity identifier:        handling 
Resource identifier:        employee 
Timestamps:     start, complete 

2.4 Data visualization

2.4.1 Processmap, frequency

#frequency: absolute, absolute_case, relative, relative_case
print(process_map(sc2_activitylog, type=frequency("absolute")))
NULL

2.4.2 Processmap, performance

#performance: median/mean, "years"/"semesters"/"quarters"/"months"/"weeks"/"days"/"hours"/"mins"/"secs"
print(process_map(sc2_activitylog, type=performance(median,"secs")))
NULL

2.4.3 Ressourcemap, frequency

resource_map(sc2_activitylog, type=frequency("absolute"))

2.4.4 Ressourcemap, performance

resource_map(sc2_activitylog, type=performance(median,"secs"))

3. Scenario 3

3.1 Read data

sc3_data <- read.csv("C:/Users/nikol/Downloads/scenario3.csv", sep=";")

3.2 Analyze data structure

head(sc3_data)

3.3 Data wrangling

sc3_activitylog <- sc3_data %>%
    # recode lifecycle variable appropriately
    dplyr::mutate(registration_type = forcats::fct_recode(registration_type, 
                                                          "start" = "started",
                                                          "complete" = "completed")) %>%
    convert_timestamps(columns = "time", format = ymd_hms) %>%
    eventlog(case_id = "patient",
                activity_id = "handling",
                activity_instance_id = "handling_id",
                lifecycle_id = "registration_type",
                timestamp = "time",
                resource_id = "employee") 
G2;H2;Warningh in validate_eventlog(eventlog) :
  The following activity instances are connected to more than one resource: 125,625,1060,1297,1859,2354g
sc3_activitylog
# Log of 12 events consisting of:
1 trace 
1 case 
6 instances of 6 activities 
6 resources 
Events occurred from 2004-05-20 17:21:29 until 2012-05-20 17:21:59 
 
# Variables were mapped as follows:
Case identifier:        patient 
Activity identifier:        handling 
Resource identifier:        employee 
Activity instance identifier:   handling_id 
Timestamp:          time 
Lifecycle transition:       registration_type 

3.4 Data visualization

3.4.1 Processmap, frequency

#frequency: absolute, absolute_case, relative, relative_case
print(process_map(sc3_activitylog, type=frequency("absolute")))
NULL

3.4.2 Processmap, performance

#performance: median/mean, "years"/"semesters"/"quarters"/"months"/"weeks"/"days"/"hours"/"mins"/"secs"
print(process_map(sc3_activitylog, type=performance(median,"secs")))
NULL

3.4.3 Ressourcemap, frequency

resource_map(sc3_activitylog, type=frequency("absolute"))

3.4.4 Ressourcemap, performance

resource_map(sc3_activitylog, type=performance(median,"secs"))

4. General presentation of the different possibilities regarding data visualization and analysis

4.1 Frequency maps

In the examples below, we will use a slightly filtered versions of the traffic_fines data set, which contains 95% of the cases that have the most frequent traces.

tmp <- traffic_fines %>%
    filter_trace_frequency(percentage = 0.95)

Absolute

Looking at the absolute-case process map below, we see that the Payment activity is only executed in 4436 cases. This number is lower than the total number of executions seen above because of the self-loop on the activity.

tmp %>%
    process_map(frequency("absolute"))

Relative

In relative terms, Payment represents 14.51% of the total activity instances. We can furthermore see that in 94.66% of cases it occurred, it was the end of the case. In the other 5.34% of cases, it was followed by another Payment.

tmp %>%
    process_map(frequency("relative"))

Relative case

Below, we see that Payment occurred in 46.24% of cases. In 2.5% of cases, a Payment activity was followed by another Payment.

tmp %>%
    process_map(frequency("relative-case"))

Relative consequent

Finally, the relative-consequent map shows us what happens before activities. With respect to Payment, we can see that it was preceded by:

Create Fine (73.15%)
Add Penalty (21.51%)
Payment (5.34%)

Payment itself represents 14.51% of all activity executions.

tmp %>%
    process_map(frequency("relative-consequent"))

4.2 Performance profile

Instead of a frequencies, process maps can also be used to visualize performance of the process, by using performance() to configure the map, instead of frequency().

There are three different parameters specific to the performance() configuration: the aggregation function, the time units, and the flow time type.

patients %>%
    process_map(performance())

Aggregation function

The FUN argument specifies the aggregation function to apply on the processing time (e.g. min, max, mean, median, etc.). By default, the mean durations are shown. We can adjust this to the maximum, for example.

patients %>%
    process_map(performance(FUN = max))
G2;H2;Warnungh: There was 1 warning in `summarize()`.
ℹ In argument: `label = do.call(...)`.
ℹ In group 10: `ACTIVITY_CLASSIFIER_ = NA` and `from_id = NA`.
Caused by warning in `type()`:
! kein nicht-fehlendes Argument für max; gebe -Inf zurückg
G2;H2;Warnungh: There were 2 warnings in `summarize()`.
The first warning was:
ℹ In argument: `value = do.call(...)`.
ℹ In group 1: `ACTIVITY_CLASSIFIER_ = "ARTIFICIAL_END"`, `next_act = NA`, `from_id = 1`, `to_id = NA`.
Caused by warning in `type()`:
! kein nicht-fehlendes Argument für max; gebe -Inf zurück
ℹ Run ]8;;ide:run:dplyr::last_dplyr_]8;;ide:run:warnings()warnings()]8;;dplyr::last_dplyr_]8;;ide:run:warnings()warnings()]8;;]8;; to see the 1 remaining warning.g

Any function that takes a numerical vector and returns a single value can be used. For example, let’s say we want to show the 0.90 percentile.

p90 <- function(x, ...) {
    quantile(x, probs = 0.9, ...)
}

patients %>%
    process_map(performance(FUN = p90))

Time units

The units argument allows to specify the time units to be used.

patients %>%
    process_map(performance(mean, "days"))
patients %>%
    process_map(performance(mean, "hours"))

4.3 Advanced maps

Combining different profiles

The profile used for nodes and edges can be differentiated using the type_nodes and type_edges attributes instead of the type argument. In this way, information about frequencies and performance, or any other value, can be combined in the same graph.

patients %>%
    process_map(type_nodes = frequency("relative_case"),
                type_edges = performance(mean))

Adding secondary information

You can add a second layer of information to both nodes and edges.

patients %>%
    process_map(type = frequency("relative_case"),
                sec = frequency("absolute"))

Both primary and secondary layers can be differentiated between nodes and edges.

patients %>%
    process_map(type_nodes =  frequency("relative_case"),
                type_edges = performance(units = "hours"),
                sec_nodes = frequency("absolute"),
                sec_edges = performance(FUN = max, units = "hours"))
G2;H2;Warnungh: There were 2 warnings in `summarize()`.
The first warning was:
ℹ In argument: `value = do.call(...)`.
ℹ In group 1: `ACTIVITY_CLASSIFIER_ = "ARTIFICIAL_END"`, `next_act = NA`, `from_id = 1`, `to_id = NA`.
Caused by warning in `type()`:
! kein nicht-fehlendes Argument für max; gebe -Inf zurück
ℹ Run ]8;;ide:run:dplyr::last_dplyr_]8;;ide:run:warnings()warnings()]8;;dplyr::last_dplyr_]8;;ide:run:warnings()warnings()]8;;]8;; to see the 1 remaining warning.g

Customizing colors

Both frequency() and performance() have the argument color_scale and color_edges to customize the colors in the process map:

color_scale: set the color scale to fill the nodes. Can be any of the scales in RColorBrewer::brewer.pal.info. Defaults to PuBu (frequency) or Reds (performance)
color_edges: any single color to apply to the arrows. Can be a named color, hex-code, or a result of rgb. Defaults to dodgerblue4 (frequency) or red4 (performance)

Configuring the colors can be useful to harmonize the process map aesthetics when using differing layers for nodes and edges.

patients %>%
    process_map(type_nodes = frequency("relative_case", color_scale = "PuBu"),
                type_edges = performance(mean, color_edges = "dodgerblue4"))

4.4 Animate Maps

Here, we use the patients event log provided by the eventdataR package.

A basic animation with static color and token size:

animate_process(patients)

Default token color, size, or image can be changed as follows:

animate_process(patients, mapping = token_aes(size = token_scale(12), shape = "rect"))
animate_process(patients, mapping = token_aes(color = token_scale("red")))
animate_process(patients, mode = "relative", jitter = 10, legend = "color",
  mapping = token_aes(color = token_scale("employee", 
    scale = "ordinal", 
    range = RColorBrewer::brewer.pal(7, "Paired"))))

4.5 Process Matrix

Absolute

traffic_fines %>%
    process_matrix(frequency("absolute")) 
traffic_fines %>%
    process_matrix(frequency("absolute")) %>%
    plot()

Relative-case

traffic_fines %>%
    process_matrix(frequency("relative-case")) 
traffic_fines %>%
    process_matrix(frequency("relative-case")) %>%
    plot()

Relative-antecedent

traffic_fines %>%
    process_matrix(frequency("relative-antecedent")) 
traffic_fines %>%
    process_matrix(frequency("relative-antecedent")) %>%
    plot()

Relative-consequent

traffic_fines %>%
    process_matrix(frequency("relative-consequent")) 
traffic_fines %>%
    process_matrix(frequency("relative-consequent")) %>%
    plot()

Performance

traffic_fines %>%
    process_matrix(performance(FUN = mean, units = "weeks")) 
traffic_fines %>%
    process_matrix(performance(FUN = mean, units = "weeks"))  %>%
    plot()

4.6 Dotted Chart

Absolute

sepsis %>%
    dotted_chart(x = "absolute")

sepsis %>%
    dotted_chart(x = "absolute", sort = "end")

Relative

sepsis %>%
    dotted_chart(x = "relative")

sepsis %>%
    dotted_chart(x = "relative_week",
                 scale_color = ggplot2::scale_color_discrete)

Relative day

sepsis %>%
    dotted_chart(x = "relative_day")

Relative week

sepsis %>%
    dotted_chart(x = "relative_week")

4.7 Trace explorer

Different activity sequences in the log can be visualized with trace_explorer(). It can be used to explore frequent as well as infrequent traces.

sepsis %>%
    trace_explorer()
G2;H2;Warnungh: No `coverage` or `n_traces` set.
! Defaulting to `coverage` = 0.2 for `type` = "frequent" traces.g

sepsis %>%
    trace_explorer(coverage = 0.15)

You can also set the coverage by directly specifying the number of traces to show.

sepsis %>%
    trace_explorer(n_traces = 10)

Instead of giving priority to frequent traces, you can show infrequent traces.

sepsis %>%
    trace_explorer(n_traces = 10, type = "infrequent")

You can set which metric to include using coverage_labels, as well as change the order.

sepsis %>%
    trace_explorer(n_traces = 10,
                   coverage_labels = c("cumulative", "relative"))

The labels shown on the traces can be configured with the arguments label_size, show_labels and abbreviate. Increasing the label size.

sepsis %>%
    trace_explorer(n_traces = 10, label_size = 4)

Removing the labels.

sepsis %>%
    trace_explorer(n_traces = 10, 
                   show_labels = FALSE)

Disabling the abbreviation of labels.

sepsis %>%
    trace_explorer(n_traces = 10, abbreviate = FALSE)

Set the colors

sepsis %>%
    trace_explorer(n_traces = 10,
                   scale_fill = ggplot2::scale_fill_discrete)

4.8 Performance Spectrum

traffic_fines %>%
    ps_detailed()

The number of segments shown in the performance spectrum can be configured in two ways. The first is to explicitly state the number of segments to show.

traffic_fines %>%
    ps_detailed(n_segments = 10)

traffic_fines %>%
    ps_detailed(classification = "resource")

traffic_fines %>%
    end_activities("case") %>%
    augment(traffic_fines, prefix = "end") %>%
    ps_detailed(classification = "end_activity")

The aggregated performance spectrum works in completely the same way.

traffic_fines %>%
    end_activities("case") %>%
    augment(traffic_fines, prefix = "end") %>%
    group_by(end_activity) %>%
    ps_aggregated()

5. Weiterführende Analysen

5.1 Control Flow

Activity Presence

Activity presence shows in what percentage of cases an activity is present. It has no level-argument.

patients %>% activity_presence() %>%
    plot

Activity frequency

patients %>%
    activity_frequency("activity")

Start activities

patients %>%
    start_activities("resource-activity")

End activities

patients %>%
    end_activities("resource-activity")

Trace Coverage

The trace coverage metric shows the relationship between the number of different activity sequences (i.e. traces) and the number of cases they cover.

patients %>%
    trace_coverage("trace") %>%
    plot()

Trance length

The trace length metric describes the length of traces, i.e. the number of activity instances for each case. It can be computed at the levels case, trace and log.

patients %>%
    trace_length("log") %>%
    plot

5.2 Performance

Idle Time

The idle time is the time that there is no activity in a case or for a resource. It can only be calculated when there are both start and end timestamps available for activity instances. It can be computed at the levels trace, resource, case and log, and using different time units.

patients %>%
    idle_time("resource", units = "days")

The output of all metrics in edeaR can be visualized by supplying it to the plot function.

patients %>%
    idle_time("resource", units = "days") %>%
    plot()

Processing Time

The processing time can be computed at the levels log, trace, case, activity and resource-activity. It can only be calculated when there are both start and end timestamps available for activity instances.

patients %>% 
    processing_time("activity") %>%
    plot

Throughput Time

The throughput time is the time form the very first event to the last event of a case. The levels at which it can be computed are log, trace, or case.

patients %>%
    throughput_time("log") %>%
    plot()

5.3 Organisational

Resource Frequency

The resource frequency metric allows the computation of the number/frequency of resources at the levels of log, case, activity, resource, and resource-activity.

patients %>%
    resource_frequency("resource")

Resource Involvment

Resource involvement refers to the notion of the number of cases in which a resource is involved. It can be computed at levels case, resource, and resource-activity.

It this example it shows that only r1 and r2 are involved in all cases, r6 and r7 are involved in most of the cases, while the others are only involved in half of the cases, more or less.

patients %>%
    resource_involvement(level = "resource") %>% plot

Resource Specialization

The resource specalization metric shows whether resources are specialized in certain activities or not. It can be calculated at the levels log, case, resource and activity.

In the simple patients event log, each resource is performing exactly one activity, and is therefore 100% specialized.

patients %>%
    resource_specialisation("resource")

Handover-of-work network

A handover-of-work network can be created with the resource_map function. It has the same arguments as the process_map function.

patients %>%
    resource_map()

Resource precedence matrix

A more compact representation of hand-over-of-work is given by the resource_matrix function, which works the same as the process matrix functions.

patients %>%
    resource_matrix() %>%
    plot()

5.4 Multi-dimensional

W O R K - I N - P R O G R E S S

LS0tDQp0aXRsZTogIlNBTVBMRSAtIEJ1c2luZXNzIFByb2Nlc3MgQW5hbHl0aWNzIC0gU0FNUExFIg0KYXV0aG9yOiBOaWtvbGEgUGF2aWENCmRhdGU6IDIwLjA1LjIwMjUNCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCk1hdGVyaWFsIGFuZCBpZGVhIFNvdXJjZTogaHR0cHM6Ly9naXRodWIuY29tL2J1cGF2ZXJzZQ0KDQojIDEuIFNjZW5hcmlvIDENCiMjIDEuMSBSZWFkIGRhdGENCmBgYHtyfQ0Kc2MxX2RhdGEgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL25pa29sL0Rvd25sb2Fkcy9zY2VuYXJpbzEuY3N2Iiwgc2VwPSI7IikNCmBgYA0KDQojIyAxLjIgQW5hbHl6ZSBkYXRhIHN0cnVjdHVyZQ0KYGBge3J9DQpoZWFkKHNjMV9kYXRhKQ0KYGBgDQojIyAxLjMgRGF0YSB3cmFuZ2xpbmcNCmBgYHtyfQ0Kc2MxX2FjdGl2aXR5bG9nIDwtIHNjMV9kYXRhICU+JQ0KICAgICMgcmVuYW1lIHRpbWVzdGFtcCB2YXJpYWJsZXMgYXBwcm9wcmlhdGVseQ0KICAgIGRwbHlyOjpyZW5hbWUoc3RhcnQgPSBhY3Rpdml0eV9zdGFydGVkLCANCiAgICAgICAgICAgY29tcGxldGUgPSBhY3Rpdml0eV9lbmRlZCkgJT4lDQogICAgIyBjb252ZXJ0IHRpbWVzdGFtcHMgdG8gDQogICAgY29udmVydF90aW1lc3RhbXBzKGNvbHVtbnMgPSBjKCJzdGFydCIsICJjb21wbGV0ZSIpLCBmb3JtYXQgPSB5bWRfaG1zKSAlPiUNCiAgICBhY3Rpdml0eWxvZyhjYXNlX2lkID0gInBhdGllbnQiLA0KICAgICAgICAgICAgICAgIGFjdGl2aXR5X2lkID0gImhhbmRsaW5nIiwNCiAgICAgICAgICAgICAgICByZXNvdXJjZV9pZCA9ICJlbXBsb3llZSIsDQogICAgICAgICAgICAgICAgdGltZXN0YW1wcyA9IGMoInN0YXJ0IiwgImNvbXBsZXRlIikpDQpgYGANCg0KIyMgMS40IERhdGEgdmlzdWFsaXphdGlvbg0KIyMgMS40LjEgUHJvY2Vzc21hcCwgZnJlcXVlbmN5DQpgYGB7cn0NCiNmcmVxdWVuY3k6IGFic29sdXRlLCBhYnNvbHV0ZV9jYXNlLCByZWxhdGl2ZSwgcmVsYXRpdmVfY2FzZQ0KcHJpbnQocHJvY2Vzc19tYXAoc2MxX2FjdGl2aXR5bG9nLCB0eXBlPWZyZXF1ZW5jeSgiYWJzb2x1dGUiKSkpDQpgYGANCg0KIyMgMS40LjIgUHJvY2Vzc21hcCwgcGVyZm9ybWFuY2UNCmBgYHtyfQ0KI3BlcmZvcm1hbmNlOiBtZWRpYW4vbWVhbiwgInllYXJzIi8ic2VtZXN0ZXJzIi8icXVhcnRlcnMiLyJtb250aHMiLyJ3ZWVrcyIvImRheXMiLyJob3VycyIvIm1pbnMiLyJzZWNzIg0KcHJpbnQocHJvY2Vzc19tYXAoc2MxX2FjdGl2aXR5bG9nLCB0eXBlPXBlcmZvcm1hbmNlKG1lZGlhbiwic2VjcyIpKSkNCmBgYA0KDQojIyAxLjQuMyBSZXNzb3VyY2VtYXAsIGZyZXF1ZW5jeQ0KYGBge3J9DQpyZXNvdXJjZV9tYXAoc2MxX2FjdGl2aXR5bG9nLCB0eXBlPWZyZXF1ZW5jeSgiYWJzb2x1dGUiKSkNCmBgYA0KDQojIyAxLjQuNSBSZXNzb3VyY2VtYXAsIHBlcmZvcm1hbmNlDQpgYGB7cn0NCnJlc291cmNlX21hcChzYzFfYWN0aXZpdHlsb2csIHR5cGU9cGVyZm9ybWFuY2UobWVkaWFuLCJzZWNzIikpDQpgYGANCg0KIyAyLiBTY2VuYXJpbyAyDQojIyAyLjEgUmVhZCBkYXRhDQpgYGB7cn0NCnNjMl9kYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9uaWtvbC9Eb3dubG9hZHMvc2NlbmFyaW8yLmNzdiIsIHNlcD0iOyIpDQpgYGANCg0KIyMgMi4yIEFuYWx5emUgZGF0YSBzdHJ1Y3R1cmUNCmBgYHtyfQ0KaGVhZChzYzJfZGF0YSkNCmBgYA0KDQojIyAyLjMgRGF0YSB3cmFuZ2xpbmcNCmBgYHtyfQ0Kc2MyX2RhdGEgJT4lDQogICAgIyByZWNvZGUgbGlmZWN5Y2xlIHZhcmlhYmxlIGFwcHJvcHJpYXRlbHkNCiAgICBkcGx5cjo6bXV0YXRlKHJlZ2lzdHJhdGlvbl90eXBlID0gZm9yY2F0czo6ZmN0X3JlY29kZShyZWdpc3RyYXRpb25fdHlwZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN0YXJ0IiA9ICJzdGFydGVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29tcGxldGUiID0gImNvbXBsZXRlZCIpKSAlPiUNCiAgICBjb252ZXJ0X3RpbWVzdGFtcHMoY29sdW1ucyA9ICJ0aW1lIiwgZm9ybWF0ID0geW1kX2htcykgJT4lDQogICAgZXZlbnRsb2coY2FzZV9pZCA9ICJwYXRpZW50IiwNCiAgICAgICAgICAgICBhY3Rpdml0eV9pZCA9ICJoYW5kbGluZyIsDQogICAgICAgICAgICAgYWN0aXZpdHlfaW5zdGFuY2VfaWQgPSAiaGFuZGxpbmdfaWQiLA0KICAgICAgICAgICAgIGxpZmVjeWNsZV9pZCA9ICJyZWdpc3RyYXRpb25fdHlwZSIsDQogICAgICAgICAgICAgdGltZXN0YW1wID0gInRpbWUiLA0KICAgICAgICAgICAgIHJlc291cmNlX2lkID0gImVtcGxveWVlIikgJT4lDQogICAgdG9fYWN0aXZpdHlsb2coKSAtPiBzYzJfYWN0aXZpdHlsb2cNCg0Kc2MyX2FjdGl2aXR5bG9nDQpgYGANCg0KIyAyLjQgRGF0YSB2aXN1YWxpemF0aW9uDQojIyAyLjQuMSBQcm9jZXNzbWFwLCBmcmVxdWVuY3kNCmBgYHtyfQ0KI2ZyZXF1ZW5jeTogYWJzb2x1dGUsIGFic29sdXRlX2Nhc2UsIHJlbGF0aXZlLCByZWxhdGl2ZV9jYXNlDQpwcmludChwcm9jZXNzX21hcChzYzJfYWN0aXZpdHlsb2csIHR5cGU9ZnJlcXVlbmN5KCJhYnNvbHV0ZSIpKSkNCmBgYA0KDQojIyAyLjQuMiBQcm9jZXNzbWFwLCBwZXJmb3JtYW5jZQ0KYGBge3J9DQojcGVyZm9ybWFuY2U6IG1lZGlhbi9tZWFuLCAieWVhcnMiLyJzZW1lc3RlcnMiLyJxdWFydGVycyIvIm1vbnRocyIvIndlZWtzIi8iZGF5cyIvImhvdXJzIi8ibWlucyIvInNlY3MiDQpwcmludChwcm9jZXNzX21hcChzYzJfYWN0aXZpdHlsb2csIHR5cGU9cGVyZm9ybWFuY2UobWVkaWFuLCJzZWNzIikpKQ0KYGBgDQoNCiMjIDIuNC4zIFJlc3NvdXJjZW1hcCwgZnJlcXVlbmN5DQpgYGB7cn0NCnJlc291cmNlX21hcChzYzJfYWN0aXZpdHlsb2csIHR5cGU9ZnJlcXVlbmN5KCJhYnNvbHV0ZSIpKQ0KYGBgDQoNCiMjIDIuNC40IFJlc3NvdXJjZW1hcCwgcGVyZm9ybWFuY2UNCmBgYHtyfQ0KcmVzb3VyY2VfbWFwKHNjMl9hY3Rpdml0eWxvZywgdHlwZT1wZXJmb3JtYW5jZShtZWRpYW4sInNlY3MiKSkNCmBgYA0KDQojIDMuIFNjZW5hcmlvIDMNCiMjIDMuMSBSZWFkIGRhdGENCmBgYHtyfQ0Kc2MzX2RhdGEgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL25pa29sL0Rvd25sb2Fkcy9zY2VuYXJpbzMuY3N2Iiwgc2VwPSI7IikNCmBgYA0KDQojIyAzLjIgQW5hbHl6ZSBkYXRhIHN0cnVjdHVyZQ0KYGBge3J9DQpoZWFkKHNjM19kYXRhKQ0KYGBgDQoNCiMjIDMuMyBEYXRhIHdyYW5nbGluZw0KYGBge3J9DQpzYzNfYWN0aXZpdHlsb2cgPC0gc2MzX2RhdGEgJT4lDQogICAgIyByZWNvZGUgbGlmZWN5Y2xlIHZhcmlhYmxlIGFwcHJvcHJpYXRlbHkNCiAgICBkcGx5cjo6bXV0YXRlKHJlZ2lzdHJhdGlvbl90eXBlID0gZm9yY2F0czo6ZmN0X3JlY29kZShyZWdpc3RyYXRpb25fdHlwZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN0YXJ0IiA9ICJzdGFydGVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29tcGxldGUiID0gImNvbXBsZXRlZCIpKSAlPiUNCiAgICBjb252ZXJ0X3RpbWVzdGFtcHMoY29sdW1ucyA9ICJ0aW1lIiwgZm9ybWF0ID0geW1kX2htcykgJT4lDQogICAgZXZlbnRsb2coY2FzZV9pZCA9ICJwYXRpZW50IiwNCiAgICAgICAgICAgICAgICBhY3Rpdml0eV9pZCA9ICJoYW5kbGluZyIsDQogICAgICAgICAgICAgICAgYWN0aXZpdHlfaW5zdGFuY2VfaWQgPSAiaGFuZGxpbmdfaWQiLA0KICAgICAgICAgICAgICAgIGxpZmVjeWNsZV9pZCA9ICJyZWdpc3RyYXRpb25fdHlwZSIsDQogICAgICAgICAgICAgICAgdGltZXN0YW1wID0gInRpbWUiLA0KICAgICAgICAgICAgICAgIHJlc291cmNlX2lkID0gImVtcGxveWVlIikgDQpzYzNfYWN0aXZpdHlsb2cNCmBgYA0KDQojIDMuNCBEYXRhIHZpc3VhbGl6YXRpb24NCiMjIDMuNC4xIFByb2Nlc3NtYXAsIGZyZXF1ZW5jeQ0KYGBge3J9DQojZnJlcXVlbmN5OiBhYnNvbHV0ZSwgYWJzb2x1dGVfY2FzZSwgcmVsYXRpdmUsIHJlbGF0aXZlX2Nhc2UNCnByaW50KHByb2Nlc3NfbWFwKHNjM19hY3Rpdml0eWxvZywgdHlwZT1mcmVxdWVuY3koImFic29sdXRlIikpKQ0KYGBgDQoNCiMjIDMuNC4yIFByb2Nlc3NtYXAsIHBlcmZvcm1hbmNlDQpgYGB7cn0NCiNwZXJmb3JtYW5jZTogbWVkaWFuL21lYW4sICJ5ZWFycyIvInNlbWVzdGVycyIvInF1YXJ0ZXJzIi8ibW9udGhzIi8id2Vla3MiLyJkYXlzIi8iaG91cnMiLyJtaW5zIi8ic2VjcyINCnByaW50KHByb2Nlc3NfbWFwKHNjM19hY3Rpdml0eWxvZywgdHlwZT1wZXJmb3JtYW5jZShtZWRpYW4sInNlY3MiKSkpDQpgYGANCg0KIyMgMy40LjMgUmVzc291cmNlbWFwLCBmcmVxdWVuY3kNCmBgYHtyfQ0KcmVzb3VyY2VfbWFwKHNjM19hY3Rpdml0eWxvZywgdHlwZT1mcmVxdWVuY3koImFic29sdXRlIikpDQpgYGANCg0KIyMgMy40LjQgUmVzc291cmNlbWFwLCBwZXJmb3JtYW5jZQ0KYGBge3J9DQpyZXNvdXJjZV9tYXAoc2MzX2FjdGl2aXR5bG9nLCB0eXBlPXBlcmZvcm1hbmNlKG1lZGlhbiwic2VjcyIpKQ0KYGBgDQoNCiMgNC4gR2VuZXJhbCBwcmVzZW50YXRpb24gb2YgdGhlIGRpZmZlcmVudCBwb3NzaWJpbGl0aWVzIHJlZ2FyZGluZyBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIGFuYWx5c2lzIA0KIyMgNC4xIEZyZXF1ZW5jeSBtYXBzDQpJbiB0aGUgZXhhbXBsZXMgYmVsb3csIHdlIHdpbGwgdXNlIGEgc2xpZ2h0bHkgZmlsdGVyZWQgdmVyc2lvbnMgb2YgdGhlIHRyYWZmaWNfZmluZXMgZGF0YSBzZXQsIHdoaWNoIGNvbnRhaW5zIDk1JSBvZiB0aGUgY2FzZXMgdGhhdCBoYXZlIHRoZSBtb3N0IGZyZXF1ZW50IHRyYWNlcy4NCmBgYHtyfQ0KdG1wIDwtIHRyYWZmaWNfZmluZXMgJT4lDQogICAgZmlsdGVyX3RyYWNlX2ZyZXF1ZW5jeShwZXJjZW50YWdlID0gMC45NSkNCmBgYA0KDQojIyMgQWJzb2x1dGUNCkxvb2tpbmcgYXQgdGhlIGFic29sdXRlLWNhc2UgcHJvY2VzcyBtYXAgYmVsb3csIHdlIHNlZSB0aGF0IHRoZSBQYXltZW50IGFjdGl2aXR5IGlzIG9ubHkgZXhlY3V0ZWQgaW4gNDQzNiBjYXNlcy4gVGhpcyBudW1iZXIgaXMgbG93ZXIgdGhhbiB0aGUgdG90YWwgbnVtYmVyIG9mIGV4ZWN1dGlvbnMgc2VlbiBhYm92ZSBiZWNhdXNlIG9mIHRoZSBzZWxmLWxvb3Agb24gdGhlIGFjdGl2aXR5Lg0KYGBge3J9DQp0bXAgJT4lDQogICAgcHJvY2Vzc19tYXAoZnJlcXVlbmN5KCJhYnNvbHV0ZSIpKQ0KYGBgDQoNCiMjIyBSZWxhdGl2ZQ0KSW4gcmVsYXRpdmUgdGVybXMsIFBheW1lbnQgcmVwcmVzZW50cyAxNC41MSUgb2YgdGhlIHRvdGFsIGFjdGl2aXR5IGluc3RhbmNlcy4gV2UgY2FuIGZ1cnRoZXJtb3JlIHNlZSB0aGF0IGluIDk0LjY2JSBvZiBjYXNlcyBpdCBvY2N1cnJlZCwgaXQgd2FzIHRoZSBlbmQgb2YgdGhlIGNhc2UuIEluIHRoZSBvdGhlciA1LjM0JSBvZiBjYXNlcywgaXQgd2FzIGZvbGxvd2VkIGJ5IGFub3RoZXIgUGF5bWVudC4NCmBgYHtyfQ0KdG1wICU+JQ0KICAgIHByb2Nlc3NfbWFwKGZyZXF1ZW5jeSgicmVsYXRpdmUiKSkNCmBgYA0KDQojIyMgUmVsYXRpdmUgY2FzZQ0KQmVsb3csIHdlIHNlZSB0aGF0IFBheW1lbnQgb2NjdXJyZWQgaW4gNDYuMjQlIG9mIGNhc2VzLiBJbiAyLjUlIG9mIGNhc2VzLCBhIFBheW1lbnQgYWN0aXZpdHkgd2FzIGZvbGxvd2VkIGJ5IGFub3RoZXIgUGF5bWVudC4NCmBgYHtyfQ0KdG1wICU+JQ0KICAgIHByb2Nlc3NfbWFwKGZyZXF1ZW5jeSgicmVsYXRpdmUtY2FzZSIpKQ0KYGBgDQoNCiMjIyBSZWxhdGl2ZSBjb25zZXF1ZW50DQpGaW5hbGx5LCB0aGUgcmVsYXRpdmUtY29uc2VxdWVudCBtYXAgc2hvd3MgdXMgd2hhdCBoYXBwZW5zIGJlZm9yZSBhY3Rpdml0aWVzLiBXaXRoIHJlc3BlY3QgdG8gUGF5bWVudCwgd2UgY2FuIHNlZSB0aGF0IGl0IHdhcyBwcmVjZWRlZCBieToNCg0KICAgIENyZWF0ZSBGaW5lICg3My4xNSUpDQogICAgQWRkIFBlbmFsdHkgKDIxLjUxJSkNCiAgICBQYXltZW50ICg1LjM0JSkNCg0KUGF5bWVudCBpdHNlbGYgcmVwcmVzZW50cyAxNC41MSUgb2YgYWxsIGFjdGl2aXR5IGV4ZWN1dGlvbnMuDQpgYGB7cn0NCnRtcCAlPiUNCiAgICBwcm9jZXNzX21hcChmcmVxdWVuY3koInJlbGF0aXZlLWNvbnNlcXVlbnQiKSkNCmBgYA0KDQojIyA0LjIgUGVyZm9ybWFuY2UgcHJvZmlsZQ0KSW5zdGVhZCBvZiBhIGZyZXF1ZW5jaWVzLCBwcm9jZXNzIG1hcHMgY2FuIGFsc28gYmUgdXNlZCB0byB2aXN1YWxpemUgcGVyZm9ybWFuY2Ugb2YgdGhlIHByb2Nlc3MsIGJ5IHVzaW5nIHBlcmZvcm1hbmNlKCkgdG8gY29uZmlndXJlIHRoZSBtYXAsIGluc3RlYWQgb2YgZnJlcXVlbmN5KCkuDQoNClRoZXJlIGFyZSB0aHJlZSBkaWZmZXJlbnQgcGFyYW1ldGVycyBzcGVjaWZpYyB0byB0aGUgcGVyZm9ybWFuY2UoKSBjb25maWd1cmF0aW9uOiB0aGUgYWdncmVnYXRpb24gZnVuY3Rpb24sIHRoZSB0aW1lIHVuaXRzLCBhbmQgdGhlIGZsb3cgdGltZSB0eXBlLg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICBwcm9jZXNzX21hcChwZXJmb3JtYW5jZSgpKQ0KYGBgDQoNCiMjIyBBZ2dyZWdhdGlvbiBmdW5jdGlvbg0KVGhlIEZVTiBhcmd1bWVudCBzcGVjaWZpZXMgdGhlIGFnZ3JlZ2F0aW9uIGZ1bmN0aW9uIHRvIGFwcGx5IG9uIHRoZSBwcm9jZXNzaW5nIHRpbWUgKGUuZy4gbWluLCBtYXgsIG1lYW4sIG1lZGlhbiwgZXRjLikuIEJ5IGRlZmF1bHQsIHRoZSBtZWFuIGR1cmF0aW9ucyBhcmUgc2hvd24uIFdlIGNhbiBhZGp1c3QgdGhpcyB0byB0aGUgbWF4aW11bSwgZm9yIGV4YW1wbGUuDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHByb2Nlc3NfbWFwKHBlcmZvcm1hbmNlKEZVTiA9IG1heCkpDQpgYGANCg0KQW55IGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSBudW1lcmljYWwgdmVjdG9yIGFuZCByZXR1cm5zIGEgc2luZ2xlIHZhbHVlIGNhbiBiZSB1c2VkLiBGb3IgZXhhbXBsZSwgbGV04oCZcyBzYXkgd2Ugd2FudCB0byBzaG93IHRoZSAwLjkwIHBlcmNlbnRpbGUuDQpgYGB7cn0NCnA5MCA8LSBmdW5jdGlvbih4LCAuLi4pIHsNCiAgICBxdWFudGlsZSh4LCBwcm9icyA9IDAuOSwgLi4uKQ0KfQ0KDQpwYXRpZW50cyAlPiUNCiAgICBwcm9jZXNzX21hcChwZXJmb3JtYW5jZShGVU4gPSBwOTApKQ0KYGBgDQoNCiMjIyBUaW1lIHVuaXRzDQpUaGUgdW5pdHMgYXJndW1lbnQgYWxsb3dzIHRvIHNwZWNpZnkgdGhlIHRpbWUgdW5pdHMgdG8gYmUgdXNlZC4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgcHJvY2Vzc19tYXAocGVyZm9ybWFuY2UobWVhbiwgImRheXMiKSkNCmBgYA0KDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHByb2Nlc3NfbWFwKHBlcmZvcm1hbmNlKG1lYW4sICJob3VycyIpKQ0KYGBgDQoNCiMjIDQuMyBBZHZhbmNlZCBtYXBzDQojIyMgQ29tYmluaW5nIGRpZmZlcmVudCBwcm9maWxlcw0KVGhlIHByb2ZpbGUgdXNlZCBmb3Igbm9kZXMgYW5kIGVkZ2VzIGNhbiBiZSBkaWZmZXJlbnRpYXRlZCB1c2luZyB0aGUgdHlwZV9ub2RlcyBhbmQgdHlwZV9lZGdlcyBhdHRyaWJ1dGVzIGluc3RlYWQgb2YgdGhlIHR5cGUgYXJndW1lbnQuIEluIHRoaXMgd2F5LCBpbmZvcm1hdGlvbiBhYm91dCBmcmVxdWVuY2llcyBhbmQgcGVyZm9ybWFuY2UsIG9yIGFueSBvdGhlciB2YWx1ZSwgY2FuIGJlIGNvbWJpbmVkIGluIHRoZSBzYW1lIGdyYXBoLg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICBwcm9jZXNzX21hcCh0eXBlX25vZGVzID0gZnJlcXVlbmN5KCJyZWxhdGl2ZV9jYXNlIiksDQogICAgICAgICAgICAgICAgdHlwZV9lZGdlcyA9IHBlcmZvcm1hbmNlKG1lYW4pKQ0KYGBgDQoNCiMjIyBBZGRpbmcgc2Vjb25kYXJ5IGluZm9ybWF0aW9uDQpZb3UgY2FuIGFkZCBhIHNlY29uZCBsYXllciBvZiBpbmZvcm1hdGlvbiB0byBib3RoIG5vZGVzIGFuZCBlZGdlcy4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgcHJvY2Vzc19tYXAodHlwZSA9IGZyZXF1ZW5jeSgicmVsYXRpdmVfY2FzZSIpLA0KICAgICAgICAgICAgICAgIHNlYyA9IGZyZXF1ZW5jeSgiYWJzb2x1dGUiKSkNCmBgYA0KDQpCb3RoIHByaW1hcnkgYW5kIHNlY29uZGFyeSBsYXllcnMgY2FuIGJlIGRpZmZlcmVudGlhdGVkIGJldHdlZW4gbm9kZXMgYW5kIGVkZ2VzLg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICBwcm9jZXNzX21hcCh0eXBlX25vZGVzID0gIGZyZXF1ZW5jeSgicmVsYXRpdmVfY2FzZSIpLA0KICAgICAgICAgICAgICAgIHR5cGVfZWRnZXMgPSBwZXJmb3JtYW5jZSh1bml0cyA9ICJob3VycyIpLA0KICAgICAgICAgICAgICAgIHNlY19ub2RlcyA9IGZyZXF1ZW5jeSgiYWJzb2x1dGUiKSwNCiAgICAgICAgICAgICAgICBzZWNfZWRnZXMgPSBwZXJmb3JtYW5jZShGVU4gPSBtYXgsIHVuaXRzID0gImhvdXJzIikpDQpgYGANCg0KIyMjIEN1c3RvbWl6aW5nIGNvbG9ycw0KQm90aCBmcmVxdWVuY3koKSBhbmQgcGVyZm9ybWFuY2UoKSBoYXZlIHRoZSBhcmd1bWVudCBjb2xvcl9zY2FsZSBhbmQgY29sb3JfZWRnZXMgdG8gY3VzdG9taXplIHRoZSBjb2xvcnMgaW4gdGhlIHByb2Nlc3MgbWFwOg0KDQogICAgY29sb3Jfc2NhbGU6IHNldCB0aGUgY29sb3Igc2NhbGUgdG8gZmlsbCB0aGUgbm9kZXMuIENhbiBiZSBhbnkgb2YgdGhlIHNjYWxlcyBpbiBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwuaW5mby4gRGVmYXVsdHMgdG8gUHVCdSAoZnJlcXVlbmN5KSBvciBSZWRzIChwZXJmb3JtYW5jZSkNCiAgICBjb2xvcl9lZGdlczogYW55IHNpbmdsZSBjb2xvciB0byBhcHBseSB0byB0aGUgYXJyb3dzLiBDYW4gYmUgYSBuYW1lZCBjb2xvciwgaGV4LWNvZGUsIG9yIGEgcmVzdWx0IG9mIHJnYi4gRGVmYXVsdHMgdG8gZG9kZ2VyYmx1ZTQgKGZyZXF1ZW5jeSkgb3IgcmVkNCAocGVyZm9ybWFuY2UpDQoNCkNvbmZpZ3VyaW5nIHRoZSBjb2xvcnMgY2FuIGJlIHVzZWZ1bCB0byBoYXJtb25pemUgdGhlIHByb2Nlc3MgbWFwIGFlc3RoZXRpY3Mgd2hlbiB1c2luZyBkaWZmZXJpbmcgbGF5ZXJzIGZvciBub2RlcyBhbmQgZWRnZXMuDQoNCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgcHJvY2Vzc19tYXAodHlwZV9ub2RlcyA9IGZyZXF1ZW5jeSgicmVsYXRpdmVfY2FzZSIsIGNvbG9yX3NjYWxlID0gIlB1QnUiKSwNCiAgICAgICAgICAgICAgICB0eXBlX2VkZ2VzID0gcGVyZm9ybWFuY2UobWVhbiwgY29sb3JfZWRnZXMgPSAiZG9kZ2VyYmx1ZTQiKSkNCmBgYA0KDQojIyA0LjQgQW5pbWF0ZSBNYXBzDQpIZXJlLCB3ZSB1c2UgdGhlIHBhdGllbnRzIGV2ZW50IGxvZyBwcm92aWRlZCBieSB0aGUgZXZlbnRkYXRhUiBwYWNrYWdlLg0KDQpBIGJhc2ljIGFuaW1hdGlvbiB3aXRoIHN0YXRpYyBjb2xvciBhbmQgdG9rZW4gc2l6ZToNCmBgYHtyfQ0KYW5pbWF0ZV9wcm9jZXNzKHBhdGllbnRzKQ0KYGBgDQoNCkRlZmF1bHQgdG9rZW4gY29sb3IsIHNpemUsIG9yIGltYWdlIGNhbiBiZSBjaGFuZ2VkIGFzIGZvbGxvd3M6DQpgYGB7cn0NCmFuaW1hdGVfcHJvY2VzcyhwYXRpZW50cywgbWFwcGluZyA9IHRva2VuX2FlcyhzaXplID0gdG9rZW5fc2NhbGUoMTIpLCBzaGFwZSA9ICJyZWN0IikpDQpgYGANCg0KYGBge3J9DQphbmltYXRlX3Byb2Nlc3MocGF0aWVudHMsIG1hcHBpbmcgPSB0b2tlbl9hZXMoY29sb3IgPSB0b2tlbl9zY2FsZSgicmVkIikpKQ0KYGBgDQoNCmBgYHtyfQ0KYW5pbWF0ZV9wcm9jZXNzKHBhdGllbnRzLCBtb2RlID0gInJlbGF0aXZlIiwgaml0dGVyID0gMTAsIGxlZ2VuZCA9ICJjb2xvciIsDQogIG1hcHBpbmcgPSB0b2tlbl9hZXMoY29sb3IgPSB0b2tlbl9zY2FsZSgiZW1wbG95ZWUiLCANCiAgICBzY2FsZSA9ICJvcmRpbmFsIiwgDQogICAgcmFuZ2UgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoNywgIlBhaXJlZCIpKSkpDQpgYGANCg0KIyMgNC41IFByb2Nlc3MgTWF0cml4DQojIyMgQWJzb2x1dGUNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwcm9jZXNzX21hdHJpeChmcmVxdWVuY3koImFic29sdXRlIikpIA0KYGBgDQoNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwcm9jZXNzX21hdHJpeChmcmVxdWVuY3koImFic29sdXRlIikpICU+JQ0KICAgIHBsb3QoKQ0KYGBgDQoNCiMjIyBSZWxhdGl2ZS1jYXNlDQpgYGB7cn0NCnRyYWZmaWNfZmluZXMgJT4lDQogICAgcHJvY2Vzc19tYXRyaXgoZnJlcXVlbmN5KCJyZWxhdGl2ZS1jYXNlIikpIA0KYGBgDQoNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwcm9jZXNzX21hdHJpeChmcmVxdWVuY3koInJlbGF0aXZlLWNhc2UiKSkgJT4lDQogICAgcGxvdCgpDQpgYGANCg0KIyMjIFJlbGF0aXZlLWFudGVjZWRlbnQNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwcm9jZXNzX21hdHJpeChmcmVxdWVuY3koInJlbGF0aXZlLWFudGVjZWRlbnQiKSkgDQpgYGANCg0KYGBge3J9DQp0cmFmZmljX2ZpbmVzICU+JQ0KICAgIHByb2Nlc3NfbWF0cml4KGZyZXF1ZW5jeSgicmVsYXRpdmUtYW50ZWNlZGVudCIpKSAlPiUNCiAgICBwbG90KCkNCmBgYA0KDQojIyMgUmVsYXRpdmUtY29uc2VxdWVudA0KYGBge3J9DQp0cmFmZmljX2ZpbmVzICU+JQ0KICAgIHByb2Nlc3NfbWF0cml4KGZyZXF1ZW5jeSgicmVsYXRpdmUtY29uc2VxdWVudCIpKSANCmBgYA0KDQpgYGB7cn0NCnRyYWZmaWNfZmluZXMgJT4lDQogICAgcHJvY2Vzc19tYXRyaXgoZnJlcXVlbmN5KCJyZWxhdGl2ZS1jb25zZXF1ZW50IikpICU+JQ0KICAgIHBsb3QoKQ0KYGBgDQoNCiMjIyBQZXJmb3JtYW5jZQ0KYGBge3J9DQp0cmFmZmljX2ZpbmVzICU+JQ0KICAgIHByb2Nlc3NfbWF0cml4KHBlcmZvcm1hbmNlKEZVTiA9IG1lYW4sIHVuaXRzID0gIndlZWtzIikpIA0KYGBgDQoNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwcm9jZXNzX21hdHJpeChwZXJmb3JtYW5jZShGVU4gPSBtZWFuLCB1bml0cyA9ICJ3ZWVrcyIpKSAgJT4lDQogICAgcGxvdCgpDQpgYGANCg0KIyMgNC42IERvdHRlZCBDaGFydA0KIyMjIEFic29sdXRlDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICBkb3R0ZWRfY2hhcnQoeCA9ICJhYnNvbHV0ZSIpDQpgYGANCg0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgZG90dGVkX2NoYXJ0KHggPSAiYWJzb2x1dGUiLCBzb3J0ID0gImVuZCIpDQpgYGANCg0KIyMjIFJlbGF0aXZlDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICBkb3R0ZWRfY2hhcnQoeCA9ICJyZWxhdGl2ZSIpDQpgYGANCg0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgZG90dGVkX2NoYXJ0KHggPSAicmVsYXRpdmVfd2VlayIsDQogICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yID0gZ2dwbG90Mjo6c2NhbGVfY29sb3JfZGlzY3JldGUpDQpgYGANCg0KIyMjIFJlbGF0aXZlIGRheQ0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgZG90dGVkX2NoYXJ0KHggPSAicmVsYXRpdmVfZGF5IikNCmBgYA0KDQojIyMgUmVsYXRpdmUgd2Vlaw0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgZG90dGVkX2NoYXJ0KHggPSAicmVsYXRpdmVfd2VlayIpDQpgYGANCg0KIyMgNC43IFRyYWNlIGV4cGxvcmVyDQpEaWZmZXJlbnQgYWN0aXZpdHkgc2VxdWVuY2VzIGluIHRoZSBsb2cgY2FuIGJlIHZpc3VhbGl6ZWQgd2l0aCB0cmFjZV9leHBsb3JlcigpLiBJdCBjYW4gYmUgdXNlZCB0byBleHBsb3JlIGZyZXF1ZW50IGFzIHdlbGwgYXMgaW5mcmVxdWVudCB0cmFjZXMuDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICB0cmFjZV9leHBsb3JlcigpDQpgYGANCg0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgdHJhY2VfZXhwbG9yZXIoY292ZXJhZ2UgPSAwLjE1KQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBzZXQgdGhlIGNvdmVyYWdlIGJ5IGRpcmVjdGx5IHNwZWNpZnlpbmcgdGhlIG51bWJlciBvZiB0cmFjZXMgdG8gc2hvdy4NCmBgYHtyfQ0Kc2Vwc2lzICU+JQ0KICAgIHRyYWNlX2V4cGxvcmVyKG5fdHJhY2VzID0gMTApDQpgYGANCg0KSW5zdGVhZCBvZiBnaXZpbmcgcHJpb3JpdHkgdG8gZnJlcXVlbnQgdHJhY2VzLCB5b3UgY2FuIHNob3cgaW5mcmVxdWVudCB0cmFjZXMuDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICB0cmFjZV9leHBsb3JlcihuX3RyYWNlcyA9IDEwLCB0eXBlID0gImluZnJlcXVlbnQiKQ0KYGBgDQoNCllvdSBjYW4gc2V0IHdoaWNoIG1ldHJpYyB0byBpbmNsdWRlIHVzaW5nIGNvdmVyYWdlX2xhYmVscywgYXMgd2VsbCBhcyBjaGFuZ2UgdGhlIG9yZGVyLg0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgdHJhY2VfZXhwbG9yZXIobl90cmFjZXMgPSAxMCwNCiAgICAgICAgICAgICAgICAgICBjb3ZlcmFnZV9sYWJlbHMgPSBjKCJjdW11bGF0aXZlIiwgInJlbGF0aXZlIikpDQpgYGANCg0KVGhlIGxhYmVscyBzaG93biBvbiB0aGUgdHJhY2VzIGNhbiBiZSBjb25maWd1cmVkIHdpdGggdGhlIGFyZ3VtZW50cyBsYWJlbF9zaXplLCBzaG93X2xhYmVscyBhbmQgYWJicmV2aWF0ZS4NCkluY3JlYXNpbmcgdGhlIGxhYmVsIHNpemUuDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICB0cmFjZV9leHBsb3JlcihuX3RyYWNlcyA9IDEwLCBsYWJlbF9zaXplID0gNCkNCmBgYA0KDQpSZW1vdmluZyB0aGUgbGFiZWxzLg0KYGBge3J9DQpzZXBzaXMgJT4lDQogICAgdHJhY2VfZXhwbG9yZXIobl90cmFjZXMgPSAxMCwgDQogICAgICAgICAgICAgICAgICAgc2hvd19sYWJlbHMgPSBGQUxTRSkNCmBgYA0KDQpEaXNhYmxpbmcgdGhlIGFiYnJldmlhdGlvbiBvZiBsYWJlbHMuDQpgYGB7cn0NCnNlcHNpcyAlPiUNCiAgICB0cmFjZV9leHBsb3JlcihuX3RyYWNlcyA9IDEwLCBhYmJyZXZpYXRlID0gRkFMU0UpDQpgYGANCg0KU2V0IHRoZSBjb2xvcnMNCmBgYHtyfQ0Kc2Vwc2lzICU+JQ0KICAgIHRyYWNlX2V4cGxvcmVyKG5fdHJhY2VzID0gMTAsDQogICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbCA9IGdncGxvdDI6OnNjYWxlX2ZpbGxfZGlzY3JldGUpDQpgYGANCg0KIyMgNC44IFBlcmZvcm1hbmNlIFNwZWN0cnVtDQpgYGB7cn0NCnRyYWZmaWNfZmluZXMgJT4lDQogICAgcHNfZGV0YWlsZWQoKQ0KYGBgDQoNClRoZSBudW1iZXIgb2Ygc2VnbWVudHMgc2hvd24gaW4gdGhlIHBlcmZvcm1hbmNlIHNwZWN0cnVtIGNhbiBiZSBjb25maWd1cmVkIGluIHR3byB3YXlzLiBUaGUgZmlyc3QgaXMgdG8gZXhwbGljaXRseSBzdGF0ZSB0aGUgbnVtYmVyIG9mIHNlZ21lbnRzIHRvIHNob3cuDQpgYGB7cn0NCnRyYWZmaWNfZmluZXMgJT4lDQogICAgcHNfZGV0YWlsZWQobl9zZWdtZW50cyA9IDEwKQ0KYGBgDQoNCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBwc19kZXRhaWxlZChjbGFzc2lmaWNhdGlvbiA9ICJyZXNvdXJjZSIpDQpgYGANCg0KYGBge3J9DQp0cmFmZmljX2ZpbmVzICU+JQ0KICAgIGVuZF9hY3Rpdml0aWVzKCJjYXNlIikgJT4lDQogICAgYXVnbWVudCh0cmFmZmljX2ZpbmVzLCBwcmVmaXggPSAiZW5kIikgJT4lDQogICAgcHNfZGV0YWlsZWQoY2xhc3NpZmljYXRpb24gPSAiZW5kX2FjdGl2aXR5IikNCmBgYA0KDQpUaGUgYWdncmVnYXRlZCBwZXJmb3JtYW5jZSBzcGVjdHJ1bSB3b3JrcyBpbiBjb21wbGV0ZWx5IHRoZSBzYW1lIHdheS4NCmBgYHtyfQ0KdHJhZmZpY19maW5lcyAlPiUNCiAgICBlbmRfYWN0aXZpdGllcygiY2FzZSIpICU+JQ0KICAgIGF1Z21lbnQodHJhZmZpY19maW5lcywgcHJlZml4ID0gImVuZCIpICU+JQ0KICAgIGdyb3VwX2J5KGVuZF9hY3Rpdml0eSkgJT4lDQogICAgcHNfYWdncmVnYXRlZCgpDQpgYGANCg0KIyA1LiBXZWl0ZXJmw7xocmVuZGUgQW5hbHlzZW4NCiMjIDUuMSBDb250cm9sIEZsb3cNCiMjIyBBY3Rpdml0eSBQcmVzZW5jZQ0KQWN0aXZpdHkgcHJlc2VuY2Ugc2hvd3MgaW4gd2hhdCBwZXJjZW50YWdlIG9mIGNhc2VzIGFuIGFjdGl2aXR5IGlzIHByZXNlbnQuIEl0IGhhcyBubyBsZXZlbC1hcmd1bWVudC4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lIGFjdGl2aXR5X3ByZXNlbmNlKCkgJT4lDQogICAgcGxvdA0KYGBgDQojIyMgQWN0aXZpdHkgZnJlcXVlbmN5DQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIGFjdGl2aXR5X2ZyZXF1ZW5jeSgiYWN0aXZpdHkiKQ0KYGBgDQoNCiMjIyBTdGFydCBhY3Rpdml0aWVzDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHN0YXJ0X2FjdGl2aXRpZXMoInJlc291cmNlLWFjdGl2aXR5IikNCmBgYA0KDQojIyMgRW5kIGFjdGl2aXRpZXMNCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgZW5kX2FjdGl2aXRpZXMoInJlc291cmNlLWFjdGl2aXR5IikNCmBgYA0KDQojIyMgVHJhY2UgQ292ZXJhZ2UNClRoZSB0cmFjZSBjb3ZlcmFnZSBtZXRyaWMgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBudW1iZXIgb2YgZGlmZmVyZW50IGFjdGl2aXR5IHNlcXVlbmNlcyAoaS5lLiB0cmFjZXMpIGFuZCB0aGUgbnVtYmVyIG9mIGNhc2VzIHRoZXkgY292ZXIuDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHRyYWNlX2NvdmVyYWdlKCJ0cmFjZSIpICU+JQ0KICAgIHBsb3QoKQ0KYGBgDQoNCiMjIyBUcmFuY2UgbGVuZ3RoDQpUaGUgdHJhY2UgbGVuZ3RoIG1ldHJpYyBkZXNjcmliZXMgdGhlIGxlbmd0aCBvZiB0cmFjZXMsIGkuZS4gdGhlIG51bWJlciBvZiBhY3Rpdml0eSBpbnN0YW5jZXMgZm9yIGVhY2ggY2FzZS4gSXQgY2FuIGJlIGNvbXB1dGVkIGF0IHRoZSBsZXZlbHMgY2FzZSwgdHJhY2UgYW5kIGxvZy4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgdHJhY2VfbGVuZ3RoKCJsb2ciKSAlPiUNCiAgICBwbG90DQpgYGANCg0KIyMgNS4yIFBlcmZvcm1hbmNlDQojIyMgSWRsZSBUaW1lDQpUaGUgaWRsZSB0aW1lIGlzIHRoZSB0aW1lIHRoYXQgdGhlcmUgaXMgbm8gYWN0aXZpdHkgaW4gYSBjYXNlIG9yIGZvciBhIHJlc291cmNlLiBJdCBjYW4gb25seSBiZSBjYWxjdWxhdGVkIHdoZW4gdGhlcmUgYXJlIGJvdGggc3RhcnQgYW5kIGVuZCB0aW1lc3RhbXBzIGF2YWlsYWJsZSBmb3IgYWN0aXZpdHkgaW5zdGFuY2VzLiBJdCBjYW4gYmUgY29tcHV0ZWQgYXQgdGhlIGxldmVscyB0cmFjZSwgcmVzb3VyY2UsIGNhc2UgYW5kIGxvZywgYW5kIHVzaW5nIGRpZmZlcmVudCB0aW1lIHVuaXRzLg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICBpZGxlX3RpbWUoInJlc291cmNlIiwgdW5pdHMgPSAiZGF5cyIpDQpgYGANCg0KVGhlIG91dHB1dCBvZiBhbGwgbWV0cmljcyBpbiBlZGVhUiBjYW4gYmUgdmlzdWFsaXplZCBieSBzdXBwbHlpbmcgaXQgdG8gdGhlIHBsb3QgZnVuY3Rpb24uDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIGlkbGVfdGltZSgicmVzb3VyY2UiLCB1bml0cyA9ICJkYXlzIikgJT4lDQogICAgcGxvdCgpDQpgYGANCg0KIyMjIFByb2Nlc3NpbmcgVGltZQ0KVGhlIHByb2Nlc3NpbmcgdGltZSBjYW4gYmUgY29tcHV0ZWQgYXQgdGhlIGxldmVscyBsb2csIHRyYWNlLCBjYXNlLCBhY3Rpdml0eSBhbmQgcmVzb3VyY2UtYWN0aXZpdHkuIEl0IGNhbiBvbmx5IGJlIGNhbGN1bGF0ZWQgd2hlbiB0aGVyZSBhcmUgYm90aCBzdGFydCBhbmQgZW5kIHRpbWVzdGFtcHMgYXZhaWxhYmxlIGZvciBhY3Rpdml0eSBpbnN0YW5jZXMuDQpgYGB7cn0NCnBhdGllbnRzICU+JSANCiAgICBwcm9jZXNzaW5nX3RpbWUoImFjdGl2aXR5IikgJT4lDQogICAgcGxvdA0KYGBgDQoNCiMjIyBUaHJvdWdocHV0IFRpbWUNClRoZSB0aHJvdWdocHV0IHRpbWUgaXMgdGhlIHRpbWUgZm9ybSB0aGUgdmVyeSBmaXJzdCBldmVudCB0byB0aGUgbGFzdCBldmVudCBvZiBhIGNhc2UuIFRoZSBsZXZlbHMgYXQgd2hpY2ggaXQgY2FuIGJlIGNvbXB1dGVkIGFyZSBsb2csIHRyYWNlLCBvciBjYXNlLg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICB0aHJvdWdocHV0X3RpbWUoImxvZyIpICU+JQ0KICAgIHBsb3QoKQ0KYGBgDQoNCiMjIDUuMyBPcmdhbmlzYXRpb25hbA0KIyMjIFJlc291cmNlIEZyZXF1ZW5jeQ0KVGhlIHJlc291cmNlIGZyZXF1ZW5jeSBtZXRyaWMgYWxsb3dzIHRoZSBjb21wdXRhdGlvbiBvZiB0aGUgbnVtYmVyL2ZyZXF1ZW5jeSBvZiByZXNvdXJjZXMgYXQgdGhlIGxldmVscyBvZiBsb2csIGNhc2UsIGFjdGl2aXR5LCByZXNvdXJjZSwgYW5kIHJlc291cmNlLWFjdGl2aXR5Lg0KYGBge3J9DQpwYXRpZW50cyAlPiUNCiAgICByZXNvdXJjZV9mcmVxdWVuY3koInJlc291cmNlIikNCmBgYA0KDQojIyMgUmVzb3VyY2UgSW52b2x2bWVudA0KUmVzb3VyY2UgaW52b2x2ZW1lbnQgcmVmZXJzIHRvIHRoZSBub3Rpb24gb2YgdGhlIG51bWJlciBvZiBjYXNlcyBpbiB3aGljaCBhIHJlc291cmNlIGlzIGludm9sdmVkLiBJdCBjYW4gYmUgY29tcHV0ZWQgYXQgbGV2ZWxzIGNhc2UsIHJlc291cmNlLCBhbmQgcmVzb3VyY2UtYWN0aXZpdHkuDQoNCkl0IHRoaXMgZXhhbXBsZSBpdCBzaG93cyB0aGF0IG9ubHkgcjEgYW5kIHIyIGFyZSBpbnZvbHZlZCBpbiBhbGwgY2FzZXMsIHI2IGFuZCByNyBhcmUgaW52b2x2ZWQgaW4gbW9zdCBvZiB0aGUgY2FzZXMsIHdoaWxlIHRoZSBvdGhlcnMgYXJlIG9ubHkgaW52b2x2ZWQgaW4gaGFsZiBvZiB0aGUgY2FzZXMsIG1vcmUgb3IgbGVzcy4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgcmVzb3VyY2VfaW52b2x2ZW1lbnQobGV2ZWwgPSAicmVzb3VyY2UiKSAlPiUgcGxvdA0KYGBgDQoNCiMjIyBSZXNvdXJjZSBTcGVjaWFsaXphdGlvbg0KVGhlIHJlc291cmNlIHNwZWNhbGl6YXRpb24gbWV0cmljIHNob3dzIHdoZXRoZXIgcmVzb3VyY2VzIGFyZSBzcGVjaWFsaXplZCBpbiBjZXJ0YWluIGFjdGl2aXRpZXMgb3Igbm90LiBJdCBjYW4gYmUgY2FsY3VsYXRlZCBhdCB0aGUgbGV2ZWxzIGxvZywgY2FzZSwgcmVzb3VyY2UgYW5kIGFjdGl2aXR5Lg0KDQpJbiB0aGUgc2ltcGxlIHBhdGllbnRzIGV2ZW50IGxvZywgZWFjaCByZXNvdXJjZSBpcyBwZXJmb3JtaW5nIGV4YWN0bHkgb25lIGFjdGl2aXR5LCBhbmQgaXMgdGhlcmVmb3JlIDEwMCUgc3BlY2lhbGl6ZWQuDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHJlc291cmNlX3NwZWNpYWxpc2F0aW9uKCJyZXNvdXJjZSIpDQpgYGANCg0KIyMjIEhhbmRvdmVyLW9mLXdvcmsgbmV0d29yaw0KQSBoYW5kb3Zlci1vZi13b3JrIG5ldHdvcmsgY2FuIGJlIGNyZWF0ZWQgd2l0aCB0aGUgcmVzb3VyY2VfbWFwIGZ1bmN0aW9uLiBJdCBoYXMgdGhlIHNhbWUgYXJndW1lbnRzIGFzIHRoZSBwcm9jZXNzX21hcCBmdW5jdGlvbi4NCmBgYHtyfQ0KcGF0aWVudHMgJT4lDQogICAgcmVzb3VyY2VfbWFwKCkNCmBgYA0KDQojIyMgUmVzb3VyY2UgcHJlY2VkZW5jZSBtYXRyaXgNCkEgbW9yZSBjb21wYWN0IHJlcHJlc2VudGF0aW9uIG9mIGhhbmQtb3Zlci1vZi13b3JrIGlzIGdpdmVuIGJ5IHRoZSByZXNvdXJjZV9tYXRyaXggZnVuY3Rpb24sIHdoaWNoIHdvcmtzIHRoZSBzYW1lIGFzIHRoZSBwcm9jZXNzIG1hdHJpeCBmdW5jdGlvbnMuDQpgYGB7cn0NCnBhdGllbnRzICU+JQ0KICAgIHJlc291cmNlX21hdHJpeCgpICU+JQ0KICAgIHBsb3QoKQ0KYGBgDQoNCiMjIDUuNCBNdWx0aS1kaW1lbnNpb25hbA0KIyMjIFcgTyBSIEsgLSBJIE4gLSBQIFIgTyBHIFIgRSBTIFMNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=